package data

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"slices"
	"strings"
	"time"

	"github.com/moby/moby/api/types/registry"
	"github.com/moby/moby/client"

	"github.com/acepanel/panel/internal/biz"
	"github.com/acepanel/panel/internal/http/request"
	"github.com/acepanel/panel/pkg/tools"
	"github.com/acepanel/panel/pkg/types"
)

type containerImageRepo struct{}

func NewContainerImageRepo() biz.ContainerImageRepo {
	return &containerImageRepo{}
}

// List 列出镜像
func (r *containerImageRepo) List() ([]types.ContainerImage, error) {
	apiClient, err := getDockerClient("/var/run/docker.sock")
	if err != nil {
		return nil, err
	}
	defer func(apiClient *client.Client) { _ = apiClient.Close() }(apiClient)

	resp, err := apiClient.ImageList(context.Background(), client.ImageListOptions{
		All: true,
	})
	if err != nil {
		return nil, err
	}

	var images []types.ContainerImage
	for _, item := range resp.Items {
		images = append(images, types.ContainerImage{
			ID:          item.ID,
			Containers:  item.Containers,
			RepoTags:    item.RepoTags,
			RepoDigests: item.RepoDigests,
			Size:        tools.FormatBytes(float64(item.Size)),
			Labels:      types.MapToKV(item.Labels),
			CreatedAt:   time.Unix(item.Created, 0),
		})
	}

	slices.SortFunc(images, func(a types.ContainerImage, b types.ContainerImage) int {
		return strings.Compare(a.ID, b.ID)
	})

	return images, nil
}

// Pull 拉取镜像
func (r *containerImageRepo) Pull(req *request.ContainerImagePull) error {
	apiClient, err := getDockerClient("/var/run/docker.sock")
	if err != nil {
		return err
	}
	defer func(apiClient *client.Client) { _ = apiClient.Close() }(apiClient)

	options := client.ImagePullOptions{}
	if req.Auth {
		authConfig := registry.AuthConfig{
			Username: req.Username,
			Password: req.Password,
		}
		encodedJSON, err := json.Marshal(authConfig)
		if err != nil {
			return err
		}
		authStr := base64.URLEncoding.EncodeToString(encodedJSON)
		options.RegistryAuth = authStr
	}

	out, err := apiClient.ImagePull(context.Background(), req.Name, options)
	if err != nil {
		return err
	}
	defer func(out client.ImagePullResponse) { _ = out.Close() }(out)

	// TODO 实现流式显示拉取进度
	return out.Wait(context.Background())
}

// Remove 删除镜像
func (r *containerImageRepo) Remove(id string) error {
	apiClient, err := getDockerClient("/var/run/docker.sock")
	if err != nil {
		return err
	}
	defer func(apiClient *client.Client) { _ = apiClient.Close() }(apiClient)

	_, err = apiClient.ImageRemove(context.Background(), id, client.ImageRemoveOptions{
		Force:         true,
		PruneChildren: true,
	})
	return err
}

// Prune 清理未使用的镜像
func (r *containerImageRepo) Prune() error {
	apiClient, err := getDockerClient("/var/run/docker.sock")
	if err != nil {
		return err
	}
	defer func(apiClient *client.Client) { _ = apiClient.Close() }(apiClient)

	_, err = apiClient.ImagePrune(context.Background(), client.ImagePruneOptions{})
	return err
}
